package base.thread_example.example06;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 采用 ReentrantLock 的 lock、unlock方式,
 * ShareData3 这种写法有点问题,就是全部线程进入wait僵死了,
 * 暂时没想清楚哪里出问题了,估计对lock 和 unlock机制理解的有点问题
 *
 */
public class LockUnlock2 {
    private static final Logger log = LoggerFactory.getLogger(LockUnlock2.class);

    public static void main(String[] args) {
        ReentrantLock lock = new ReentrantLock();
        ShareData3 sd = new ShareData3(lock);

        Condition aCondition = lock.newCondition();
        Condition bCondition = lock.newCondition();
        Condition cCondition = lock.newCondition();

        new Thread(()->{
            while (true) {
                try {
                    sd.print("a", aCondition, bCondition);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"t-1").start();

        new Thread(()->{
            while (true) {
                try {
                    sd.print("b", bCondition, cCondition);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"t-2").start();

        new Thread(()->{
            while (true) {
                try {
                    sd.print("c", cCondition, aCondition);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"t-3").start();

        // 注意:这里用main线程唤醒让t1线程执行输出a
        lock.lock();
        try {
            log.info("{} 开始唤醒 t1 线程输出a", Thread.currentThread().getName());
            aCondition.signal();//将a休息室唤醒,待main线程执行完，a线程开始执行
        }finally {
            lock.unlock();
        }
    }
}

/**
 * 1.需要 Lock 对象传递给ShareData3 作为锁来控制ShareDate3共享数据安全,那我就直接继承Lock,让共享数据本身就是一把锁.
 * 2.Condition 是用来根据条件判断通信的,要么进入等待,要么被唤醒,那么 print()方法的逻辑打印输出->等待->唤醒下一个,
 * 等待,唤醒并没有顺序问题,可以先都进入等待,然后从唤醒输出a开始.
 *

class ShareData3 extends ReentrantLock {
    private static final Logger log = LoggerFactory.getLogger(ShareData2.class);

    public void print(String s, Condition currentCondition, Condition nextCondition) throws InterruptedException {
        this.lock();
        try {
            currentCondition.await();// 所有线程进来就进入各自的休息室休息,释放锁
            log.info("{}:{}", Thread.currentThread().getName(), s);
            nextCondition.signalAll();// 唤醒下一个
        }finally {
            this.unlock();
        }
    }
}
*/

class ShareData3{
    private static final Logger log = LoggerFactory.getLogger(ShareData2.class);
    private ReentrantLock lock;
    public ShareData3(ReentrantLock lock){
        this.lock = lock;
    }

    public void print(String s, Condition currentCondition, Condition nextCondition) throws InterruptedException {
        lock.lock();
        try {
            currentCondition.await();
            log.info("{}:{}", Thread.currentThread().getName(), s);
            nextCondition.signalAll();
        }finally {
            lock.unlock();
        }
    }
}
